﻿using System;
using System.Collections.Generic;
using UnityEngine;

public partial class Entity : IDisposable
{
    public long instanceId { get; protected set; }

    private Dictionary<long, Entity> children;
    private Dictionary<long, Entity> components;
#if UNITY_EDITOR
    GameObject viewGo;
#endif

    private Entity parent;
    public Entity Parent
    {
        get
        {
            return parent;
        }
        set
        {
            parent = value;
            value.AddChild(this);
            instanceId = IdGenerater.GenerateId();

            if (parent != null)
            {
                viewGo.transform.SetParent(parent.viewGo.transform);
            }
        }
    }

    protected Entity()
    {
#if UNITY_EDITOR
        viewGo = new GameObject(this.GetType().ToString());
#endif
    }

    void AddChild(Entity entity)
    {
        if (children == null)
        {
            children = new Dictionary<long, Entity>();
        }
        children[entity.instanceId] = entity;
    }

    public void Remove(Entity entity)
    {
        if (children == null)
            return;

        children.Remove(entity.instanceId);
    }

    public Entity AddComponent(Type type)
    {
        var component = Activator.CreateInstance(type) as Entity;

        if(components == null)
            components = new Dictionary<long, Entity>();

        components[type.TypeHandle.Value.ToInt64()] = component;
        component.parent = this;

        return component;
    }

    public T AddComponent<T>()where T : Entity
    {
        var component = AddComponent(typeof(T)) as T;
        (component as IAwake)?.Awake();
        return component;
    }
    public T AddComponent<T, A>(A a) where T : Entity
    {
        var component = AddComponent(typeof(T)) as T;
        (component as IAwake<A>)?.Awake(a);
        return component;
    }
    public T AddComponent<T, A, A1>(A a, A1 a1) where T : Entity
    {
        var component = AddComponent(typeof(T)) as T;
        (component as IAwake<A, A1>)?.Awake(a, a1);
        return component;
    }
    public T AddComponent<T, A, A1, A2>(A a, A1 a1, A2 a2) where T : Entity
    {
        var component = AddComponent(typeof(T)) as T;
        (component as IAwake<A, A1, A2>)?.Awake(a, a1, a2);
        return component;
    }

    public virtual void Dispose()
    {
        if(components != null)
        {
            foreach (var component in components.Values)
            {
                component.Dispose();
            }
            components = null;
        }

        if(children != null)
        {
            foreach (var child in children.Values)
            {
                child.Dispose();
            }
            children = null;
        }

        parent?.Remove(this);
        parent = null;
    }
}
